查看原文
其他

业务优化案例一则

yangyidba yangyidba 2019-06-04

背景

前一段时间著名的"开封菜"在有赞开通了小程序,为了推广其小程序,他们从8月6号开始每天10点做拼团活动,1万人或者2000人成团,用户购买之后可以进行分享给朋友进行裂变。 以上是活动的基础场景。

做活动之前还担心我们的MySQL能不能扛住大流量的压力,现在看来其实根本不用担心,因为"墨菲定律"告诉我们:如果你担心某种情况发生,那么它就更有可能发生。

现象

8.6-8.10的拼团活动还算顺利,但是因为前面几次的预热到周六消费高峰的时候,瞬时压力是平时的3倍,导致db thread_running飙高到250左右,基本不能对外提供服务。

从 innodb status 里面查看236个会话请求都在等待排队处理,23个正在被执行。

排查

相信很多人遇到类似的情况,因为业务或者数据库瞬时出现问题,人接收到报警,再等登陆到db服务器上其实已经滞后起码3-5min了,此时"案发现场"没有得到有效记录,导致排查瞬时的问题变得非常困得。基于此种问题,我们在ZanDB系统开发了数据库服务器性能快照功能,当探测到出现性能问题时,比如thread_running飙高超过24,就记录会话,io ,innodb数据到指定的文件,方便排查。

通过慢查询日志以及当时的processlist_3343.文件分析,我们找到一条可疑的SQL,出现问题的时刻,该sql占用大部分innodb处理通道。

select id,kdt_id,order_no,activity_id,xxxxx where xxid =110 and group_id=119 and is_pay=1 order by id ASC limit 100;

该sql每次执行耗时10ms左右,执行计划显示使用"Using where; Using filesort"。 我们从开发同学那边了解到该sql承担了获取最新成交买家记录的功能,如图(10个微信头像):

大致的情况可以还原:10点开始抢购拼团时,大量流量进来,每次用户点击开团购买按钮都会触发一次查询DB的请求,周六的流量是前面几次的2-3倍,导致之前隐藏的问题出现了。

复现

为了验证我们的猜想,我们将表逻辑导出一份到测试库,使用mysqlslap进行压测。

mysqlslap --no-defaults -uroot --create-schema=ump -S /srv/my3308/run/mysql.sock --number-of-queries=1000000 --concurrency=28 --query="begin;select id,xxxid,xxxx,zz,aa,bbfrom yy where xxxid =110 and xxxid=119 and is_pay=1 order by id ASC limit 100;commit;"

压测结果

并发设置为288 模拟生产中出现问题的时候的情况。

mysqlslap --no-defaults -uroot --create-schema=ump -S /srv/my3308/run/mysql.sock --number-of-queries=1000000 --concurrency=288 --query="begin;select id,xxxid,xxxx,zz,aa,bbfrom yy where xxxid =110 and xxxid=119 and is_pay=1 order by id ASC limit 100;commit;" 压测结果 

通过上面的压测可以看出:使用线上的业务sql 并发28,280进行压测,发现usr cpu飙高到43而且thread_running会话已经占满innodb_thread_concurrency, 并发280时已经出现严重的排队,导致其他正常的请求大量延迟,出现超时。

如果将limit 减少为10 呢?设置并发度为28压测

mysqlslap --no-defaults -uroot --create-schema=ump -S /srv/my3308/run/mysql.sock --number-of-queries=1000000 --concurrency=28 --query="begin;select id,xxxid,xxxx,zz,aa,bbfrom yy where xxxid =110 and xxxid=119 and is_pay=1;commit;"

设置并发度为288压测的压测结果

从上面的测试结果来看 减少获取数据量的个数以及去掉不必要的order by 排序,qps性能有50倍的提升。不过及时limit 10,高并发依然会带来数据库稳定性风险。还需要进一步优化。

解决

至此性能问题得以发现,如何解决呢?调整索引?减少排序?我们从源头上分析,该sql的功能是展示最新已经付款的人员,是否需要最新?如果是最开始成交的10个人是否ok?实际上参加活动的人关心的是自己是否参团成功,至于其他人谁参加了,对自己没有影响。具体的优化建议:

  1. 去掉order by id ,减少不必要的排序。

  2. 修改limit 100 为limit 10 ,因为前端页面展示只需要10个人即可。

  3. 缓存参团成功的人员信息,没有必要每个人点击参团页面都要查询db。

闲扯

性能优化是一件很有意思的事情。我们可以使用一张图来阐述数据库优化的核心思想:

                                              (图片来自斗佛的blog)

这张漏斗优化法则可以使用“三减少一增加”来概括,减少磁盘访问,减少网络传输,减少CPU以及内存开销,增加硬件资源。 从图中我们可以看到优化业务效果最显著的是 减少对数据(存储)的访问。此次案例也是一样,减少不必要的数据拉取和额外的排序,性能提升显著。


    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存